package timing.ukulele.storage.controller;


import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import timing.ukulele.common.data.ResponseData;
import timing.ukulele.storage.entity.GroupEntity;
import timing.ukulele.storage.entity.NodeEntity;
import timing.ukulele.storage.entity.UserEntity;
import timing.ukulele.storage.service.GroupService;
import timing.ukulele.storage.service.NodeService;
import timing.ukulele.storage.service.PreviewService;
import timing.ukulele.storage.service.UserService;
import timing.ukulele.storage.vo.NodeTreeVO;
import timing.ukulele.web.controller.BaseController;

import java.util.Date;
import java.util.List;
import java.util.UUID;

@RestController
@RequestMapping("/node")
@Slf4j
@Tag(name = "用户存储对象相关操作")
public class NodeController extends BaseController {
    private final NodeService nodeService;
    private final UserService userService;
    private final GroupService groupService;
    private final PreviewService previewService;

    public NodeController(NodeService nodeService, UserService userService, GroupService groupService, PreviewService previewService) {
        this.nodeService = nodeService;
        this.userService = userService;
        this.groupService = groupService;
        this.previewService = previewService;
    }

    @PostMapping("/upload")
    @Operation(summary = "上传对象。单个对象的最大大小限制在5TB。putObject在对象大于5MiB时，自动使用multiple parts方式上传。这样，当上传失败时，客户端只需要上传未成功的部分即可（类似断点上传）。上传的对象使用MD5SUM签名进行完整性验证。")
    public ResponseData<NodeEntity> putObject(
            @Parameter(description = "文件名称", name = "parentId", in = ParameterIn.QUERY) @RequestParam(value = "parentId", required = false) String parentId,
            @Parameter(description = "用户权限", name = "userAuthority", in = ParameterIn.QUERY) @RequestParam(value = "userAuthority", required = false) Short userAuthority,
            @Parameter(description = "组权限", name = "groupAuthority", in = ParameterIn.QUERY) @RequestParam(value = "groupAuthority", required = false) Short groupAuthority,
            @Parameter(description = "其他人权限", name = "otherAuthority", in = ParameterIn.QUERY) @RequestParam(value = "otherAuthority", required = false) Short otherAuthority,
            @Parameter(description = "文件", name = "file") @RequestParam("file") MultipartFile file,
            @RequestHeader("account") String account) {
        try {
            if (file == null || account == null) {
                return paraErrorResponse(null, "参数错误!");
            }
            if (userAuthority != null && (userAuthority < 0 || userAuthority > 7)) {
                return paraErrorResponse(null, "用户权限错误!");
            }
            if (groupAuthority != null && (groupAuthority < 0 || groupAuthority > 7)) {
                return paraErrorResponse(null, "组权限错误!");
            }
            if (otherAuthority != null && (otherAuthority < 0 || otherAuthority > 7)) {
                return paraErrorResponse(null, "其他人权限错误!");
            }
            NodeEntity entity = new NodeEntity();
            entity.setName(file.getOriginalFilename());
            entity.setParentId(parentId);
            entity.setOwner(account);
            entity.setSize(file.getSize());
            entity.setContentType(file.getContentType());
            entity.setCreator(account);
            entity.setCreatTime(new Date());
            if (groupAuthority != null) {
                entity.setGroupAuthority(groupAuthority);
            }
            if (otherAuthority != null) {
                entity.setOtherAuthority(otherAuthority);
            }
            if (userAuthority != null) {
                entity.setUserAuthority(userAuthority);
            }
            String objectName = UUID.randomUUID() + entity.getName().substring(entity.getName().lastIndexOf("."));
            entity.setPath(objectName);
//            entity.setPreviewPath(getPreviewPath(entity));
            ResponseData<NodeEntity> response = this.nodeService.addFile(entity, account, objectName, file.getInputStream(), file.getContentType());
//            previewService.addWorkQueue(entity);
            previewService.publishPreviewEvent(entity);
            return response;
        } catch (Exception e) {
            log.error(e.getMessage());
            return failResponse(null, e.getMessage());
        }
    }

    @PostMapping("/{team}/upload")
    @Operation(summary = "上传共享柜对象。单个对象的最大大小限制在5TB。putObject在对象大于5MiB时，自动使用multiple parts方式上传。这样，当上传失败时，客户端只需要上传未成功的部分即可（类似断点上传）。上传的对象使用MD5SUM签名进行完整性验证。")
    public ResponseData<NodeEntity> putShareObject(
            @Parameter(description = "组标识", name = "team", in = ParameterIn.PATH) @PathVariable(value = "team") String team,
            @Parameter(description = "文件名称", name = "parentId", in = ParameterIn.QUERY) @RequestParam(value = "parentId", required = false) String parentId,
            @Parameter(description = "文件", name = "file") @RequestParam("file") MultipartFile file,
            @RequestHeader("account") String account) {
        try {
            if (file == null || account == null) {
                return paraErrorResponse(null, "参数错误!");
            }
            NodeEntity entity = new NodeEntity();
            entity.setName(file.getOriginalFilename());
            entity.setParentId(parentId);
            entity.setOwner(team);
            entity.setCreator(account);
            entity.setCreatTime(new Date());
            entity.setSize(file.getSize());
            entity.setContentType(file.getContentType());
            entity.setUserAuthority((short) 7);
            entity.setGroupAuthority((short) 3);
            entity.setOtherAuthority((short) 3);
            String objectName = UUID.randomUUID() + entity.getName().substring(entity.getName().lastIndexOf("."));
            entity.setPath(objectName);
//            entity.setPreviewPath(getPreviewPath(entity));
            ResponseData<NodeEntity> response = this.nodeService.addFile(entity, team, objectName, file.getInputStream(), file.getContentType());
//            previewService.addWorkQueue(entity);
            previewService.publishPreviewEvent(entity);
            return response;
        } catch (Exception e) {
            log.error(e.getMessage());
            return failResponse(null, e.getMessage());
        }
    }

//    private String getPreviewPath(NodeEntity node) {
//        if (node.getContentType().contains("image") || node.getContentType().contains("video") || node.getContentType().contains("pdf")) {
//            return node.getPath();
//        } else {
//            if ("folder".equalsIgnoreCase(node.getType()) || "unknown".equalsIgnoreCase(node.getType())) {
//                return "";
//            }
//            return node.getPath().substring(0, node.getPath().lastIndexOf(".")) + ".pdf";
//        }
//    }

    @PutMapping("/permission")
    @Operation(summary = "修改节点属性(权限)")
    public ResponseData<NodeEntity> modifyFile(
            @Parameter(description = "文件名称", name = "id", in = ParameterIn.QUERY) @RequestParam(value = "id") String fileId,
            @Parameter(description = "用户权限", name = "userAuthority", in = ParameterIn.QUERY) @RequestParam(value = "userAuthority") Short userAuthority,
            @Parameter(description = "组权限", name = "groupAuthority", in = ParameterIn.QUERY) @RequestParam(value = "groupAuthority", required = false) Short groupAuthority,
            @Parameter(description = "其他人权限", name = "otherAuthority", in = ParameterIn.QUERY) @RequestParam(value = "otherAuthority", required = false) Short otherAuthority,
            @RequestHeader("account") String account,
            @RequestHeader("role") String role) {
        if (userAuthority < 0 || userAuthority > 7) {
            return paraErrorResponse(null, "用户权限错误!");
        }
        if (groupAuthority != null && (groupAuthority < 0 || groupAuthority > 7)) {
            return paraErrorResponse(null, "组权限错误!");
        }
        if (otherAuthority != null && (otherAuthority < 0 || otherAuthority > 7)) {
            return paraErrorResponse(null, "其他人权限错误!");
        }
        try {
            return nodeService.modifyNodePermission(fileId, userAuthority, groupAuthority == null ? 0 : groupAuthority,
                    otherAuthority == null ? 0 : otherAuthority, account, role);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return failResponse(null, "权限设置失败！");
    }

    @PostMapping("/folder")
    @Operation(summary = "新建文件夹")
    public ResponseData<NodeEntity> addFolder(@RequestBody NodeEntity node,
                                              @RequestHeader("account") String account) {
        if (node == null || !StringUtils.hasLength(node.getName())) {
            return failResponse(null, "名称必传");
        }
        if (node.getUserAuthority() != null && (node.getUserAuthority() < 0 || node.getUserAuthority() > 7)) {
            return paraErrorResponse(null, "用户权限错误!");
        }
        if (node.getGroupAuthority() != null && (node.getGroupAuthority() < 0 || node.getGroupAuthority() > 7)) {
            return paraErrorResponse(null, "组权限错误!");
        }
        if (node.getOtherAuthority() != null && (node.getOtherAuthority() < 0 || node.getOtherAuthority() > 7)) {
            return paraErrorResponse(null, "其他人权限错误!");
        }
        node.setCreator(account);
        return nodeService.addFolder(node, account);
    }

    @PostMapping("/{team}/folder")
    @Operation(summary = "新共享柜建文件夹")
    public ResponseData<NodeEntity> addShareFolder(
            @Parameter(description = "小组", name = "team", in = ParameterIn.PATH) @PathVariable("team") String team,
            @RequestBody NodeEntity node, @RequestHeader("account") String account) {
        if (node == null || !StringUtils.hasLength(node.getName())) {
            return failResponse(null, "名称必传");
        }
        node.setCreator(account);
        node.setCreatTime(new Date());
        node.setUserAuthority((short) 7);
        node.setGroupAuthority((short) 3);
        node.setOtherAuthority((short) 3);
        return nodeService.addFolder(node, team);
    }

    @PutMapping("/folder")
    @Operation(summary = "修改文件夹（名称和权限）")
    public ResponseData<NodeEntity> modifyFolder(@RequestBody NodeEntity node, @RequestHeader("account") String account,
                                                 @RequestHeader("role") String role) {
        if (node == null || !StringUtils.hasLength(node.getId())) {
            return failResponse(null, "名称和Id必传");
        }
        if (!StringUtils.hasLength(node.getName())) {
            return failResponse(null, "名称必传");
        }
        if (node.getUserAuthority() != null && (node.getUserAuthority() < 0 || node.getUserAuthority() > 7)) {
            return paraErrorResponse(null, "用户权限错误!");
        }
        if (node.getGroupAuthority() != null && (node.getGroupAuthority() < 0 || node.getGroupAuthority() > 7)) {
            return paraErrorResponse(null, "组权限错误!");
        }
        if (node.getOtherAuthority() != null && (node.getOtherAuthority() < 0 || node.getOtherAuthority() > 7)) {
            return paraErrorResponse(null, "其他人权限错误!");
        }
        return nodeService.modifyFolder(node, account, role);
    }

    @PutMapping("/{team}/folder")
    @Operation(summary = "修改共享柜文件夹（名称和权限）")
    public ResponseData<NodeEntity> modifyShareFolder(@Parameter(description = "小组", name = "role", in = ParameterIn.PATH) @PathVariable("team") String team, @RequestBody NodeEntity node, @RequestHeader("account") String account,
                                                      @RequestHeader("role") String role) {
        if (node == null || !StringUtils.hasLength(node.getId()) || !StringUtils.hasLength(node.getName())) {
            return failResponse(null, "名称和Id必传");
        }
        NodeEntity entity = new NodeEntity();
        entity.setId(node.getId());
        entity.setName(node.getName());
        entity.setOwner(team);
        return nodeService.modifyFolder(node, account, role);
    }

    @DeleteMapping("/folder")
    @Operation(summary = "删除文件夹")
    public ResponseData<Boolean> removeFolder(@Parameter(description = "文件夹id", name = "id", in = ParameterIn.QUERY) @RequestParam("id") String folderId,
                                              @RequestHeader("account") String account,
                                              @RequestHeader("role") String role) {
        return nodeService.removeFolder(folderId, account, role);
    }

    @DeleteMapping("/{team}/folder")
    @Operation(summary = "删除共享柜文件夹")
    public ResponseData<Boolean> removeShareFolder(
            @Parameter(description = "小组", name = "team", in = ParameterIn.PATH) @PathVariable("team") String team,
            @Parameter(description = "文件夹id", name = "id", in = ParameterIn.QUERY) @RequestParam("id") String folderId,
            @RequestHeader("account") String account, @RequestHeader("role") String role) {
        return nodeService.removeFolder(folderId, account, role);
    }

    @DeleteMapping
    @Operation(summary = "删除文件")
    public ResponseData<NodeEntity> removeFile(@Parameter(description = "文件id", name = "fileId", in = ParameterIn.QUERY) @RequestParam("id") String fileId, @RequestHeader("account") String account,
                                               @RequestHeader("role") String role) {
        try {
            return nodeService.removeFile(fileId, account, role);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return errorResponse(null, "删除失败");
    }

    @DeleteMapping("/share")
    @Operation(summary = "删除共享柜文件")
    public ResponseData<NodeEntity> removeShareFile(@Parameter(description = "文件id", name = "id", in = ParameterIn.QUERY) @RequestParam("id") String fileId,
                                                    @RequestHeader("account") String account, @RequestHeader("role") String role) {
        try {
            return nodeService.removeFile(fileId, account, role);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return errorResponse(null, "删除失败");
    }

    @GetMapping("/download")
    @Operation(summary = "下载文件")
    public void downFile(@Parameter(description = "文件id", name = "id", in = ParameterIn.QUERY) @RequestParam("id") String fileId, @RequestHeader("account") String account,
                         HttpServletResponse response) {
        NodeTreeVO nodeTree = this.nodeService.getNodeTree(fileId);
        if (nodeTree != null) {
            this.nodeService.zipFile(nodeTree, response);
        }
    }

    @GetMapping("/node")
    @Operation(summary = "获取用户的节点")
    public ResponseData<List<NodeEntity>> getUserNode(
            @Parameter(description = "父节点id", name = "parentId", in = ParameterIn.QUERY) @RequestParam(value = "parentId", required = false, defaultValue = "0") String parentId,
            @RequestHeader("account") String account) {
        List<NodeEntity> list = this.nodeService.getUserNode(parentId, account);
        return successResponse(list);
    }

    @GetMapping("/{team}/node")
    @Operation(summary = "获取共享柜节点")
    public ResponseData<List<NodeEntity>> getShareNode(@Parameter(description = "小组", name = "team", in = ParameterIn.PATH) @PathVariable("team") String team,
                                                       @RequestParam(value = "parentId", required = false, defaultValue = "0") String parentId) {
        List<NodeEntity> list = this.nodeService.getUserNode(parentId, team);
        return successResponse(list);
    }

    @GetMapping("/node/type")
    @Operation(summary = "获取用户的节点")
    public ResponseData<List<NodeEntity>> getUserNodeByTypes(
            @RequestParam List<String> types,
            @RequestHeader("account") String account) {
        List<NodeEntity> list = this.nodeService.getUserNodeByTypes(account, types);
        return successResponse(list);
    }

    @GetMapping("/my/group")
    @Operation(summary = "用户的组信息")
    public ResponseData<List<GroupEntity>> group(@RequestHeader("account") String account) {
        UserEntity user = userService.findByAccount(account);
        if (user == null)
            return failResponse(null, "不存在该用户");
        List<String> groups = user.getGroup();
        List<GroupEntity> groupList = groupService.getByIds(groups);
        return successResponse(groupList);
    }

    public ResponseData<Boolean> copyFile(@RequestParam("fileId") String fileId, @RequestHeader("account") String account) {
        return errorResponse(null, "复制失败，尚未开发");
    }

    public ResponseData<Boolean> move(@RequestParam("fileId") String fileId, @RequestHeader("account") String account) {
        return errorResponse(null, "移动失败，尚未开发");
    }

    public ResponseData<Boolean> changeOwner(@RequestParam("fileId") String fileId, @RequestHeader("account") String account) {
        return errorResponse(null, "移交失败，尚未开发");
    }
}
